<?php
/**
 * dbfront
 * (c) 2010-2013 Stephen Adkins <spadkins@gmail.com>
 * This software began development in 2010.
 * It is based on code dating from 1999.
 *
 * License: GPL 2.0
 * The contents of this file may be used under the terms of
 * the GNU General Public License Version 2 or later (the "GPL").
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 * */

# Get rid of this error using the following PHPUnit comments.
#     PDOException: You cannot serialize or unserialize PDO instances
/**
 * @backupGlobals          disabled
 * @backupStaticAttributes disabled
 */

class APIServiceAuthTest extends PHPUnit_Framework_TestCase {
    private static $ua, $fh, $http_user_agent, $client_connection_token, $username, $password, $email, $password_hash, $session_expire_dttm, $auth_token;
    public static function setUpBeforeClass () {
        global $context, $options;

        self::$email    = 'scott9876@mailinator.com';
        self::$password = 'tiger';
        self::$username = 'scott';
        self::$http_user_agent = 'PHP/curl (phpunit) Internal Test Suite';
        self::$client_connection_token = '29426efc143b2d5511f46e38c358e92f0d313cf8d39bc9abe23547ad0caad6a8';

        # These variables are necessary for computing the client_connection_token
        $_SERVER['REMOTE_ADDR']     = '127.0.0.1';
        $_SERVER['HTTP_USER_AGENT'] = self::$http_user_agent;

        self::$ua = curl_init();

        $result = curl_setopt(self::$ua, CURLOPT_USERAGENT, self::$http_user_agent);
        $result = curl_setopt(self::$ua, CURLOPT_RETURNTRANSFER, true);

        $prefix = $options['prefix'];
        if ($prefix[0] !== '/') {
            $prefix = getcwd() . '/' . $prefix;
        }
        $result = curl_setopt(self::$ua, CURLOPT_COOKIE, "appdata=$prefix");

        self::$fh = fopen("out/APIServiceAuthTest.out", "w");

        $authdb = $context->authdb();
        #$authdb->execute('delete from auth_group_user_memb');
        #$authdb->execute('delete from auth_group');
        #$authdb->execute('delete from auth_user');
        #$authdb->execute('delete from auth_user_email');
        #$authdb->execute('delete from auth_user_password');
        #$authdb->execute('delete from auth_owner');
        #$authdb->execute('delete from auth_app');

        #$authdb->execute("insert into auth_app (app_id, app_cd, app_name, public_ind) values (1, 'dbfront',   'Database Workbench',                 'Y')");
        #$authdb->execute("insert into auth_app (app_id, app_cd, app_name, public_ind) values (2, 'sitefront', 'Site Management Workbench',          'N')");
        #$authdb->execute("insert into auth_app (app_id, app_cd, app_name, public_ind) values (3, 'appfront',  'Application Installation Workbench', 'N')");
        #$authdb->execute("insert into auth_owner (owner_id, owner_name, owner_type) values (1, 'all-users', 'G')");
        #$authdb->execute("insert into auth_owner (owner_id, owner_name, owner_type) values (2, 'system', 'G')");
        #$authdb->execute("insert into auth_user (user_id, username, password_hash, status, salt, algorithm) values (1, 'guest',  'xxxxxx', 'X', 'xxxxxx', 'xxxxxx')");
        #$authdb->execute("insert into auth_user (user_id, username, password_hash, status, salt, algorithm) values (2, 'system', 'xxxxxx', 'X', 'xxxxxx', 'xxxxxx')");
        #$authdb->execute("insert into auth_group (group_id, group_name, group_long_name, owner_user_id, public_ind) values (1, 'all-users', 'All Users', 1, 'Y')");
        #$authdb->execute("insert into auth_group (group_id, group_name, group_long_name, owner_user_id, public_ind) values (2, 'system',    'System',    1, 'N')");
        #$authdb->execute("insert into auth_group_user_memb (group_id, user_id) values (2, 2)");
    }
    public function setUp () {}

    public static function tearDownAfterClass () {
        global $context, $options;
        fclose(self::$fh);
    }
    public function tearDown () {}

    /** 
     * @group   min
     */
    public function testConnect () {
        global $context, $options;
        $inputs = array();
        $response = $this->callAjax('testConnect', 'connect', $inputs);
        $this->assertTrue(isset($response['success']));
        $this->assertEquals($response['success'], true);
        $this->assertTrue(isset($response['client_connection_token']));
        $this->assertEquals($response['client_connection_token'], self::$client_connection_token);
        #self::$client_connection_token = $response['client_connection_token'];
        return($response);
    }

#    /** 
#     * @depends testConnect
#     * @group   min
#     */
#    public function testUserAuthInfoWhereUserNotFound () {
#        global $context, $options;
#        $inputs = array(
#            'user_token'              => self::$email,
#            'client_connection_token' => self::$client_connection_token
#        );
#        $response = $this->callAjax('testUserAuthInfoWhereUserNotFound', 'user_auth_info', $inputs);
#        $this->assertEquals($response['success'], false);
#        $authdb = $context->authdb();
#        $user = $authdb->get_hash('select user_id, email from auth_user where email = ?', array($inputs['user_token']));
#        $this->assertNull($user);
#    }

#    /** 
#     * @depends testUserAuthInfoWhereUserNotFound
#     * @group   min
#     */
#    public function testReserveUserWhereUserIsSigningUp () {
#        global $context, $options;
#        $inputs = array(
#            'user_token'                => self::$email,
#            'client_connection_token'   => self::$client_connection_token,
#            'recaptcha_challenge_field' => '',
#            'recaptcha_response_field'  => ''
#        );
#        $response = $this->callAjax('testReserveUserWhereUserIsSigningUp', 'reserve_user', $inputs);
#        $this->assertEquals($response['success'], 1);
#        $this->assertTrue(isset($response['user_id']));
#        $this->assertTrue(isset($response['email']));
#        $this->assertTrue(isset($response['user_salt']));
#        $this->assertTrue(isset($response['algorithm']));
#        $this->assertTrue(isset($response['algorithm_option']));
#        $this->assertEquals($response['email'], $inputs['email']);

#        $authdb = $context->authdb();
#        $user = $authdb->get_hash('select user_id, email, salt, algorithm, algorithm_option, status, unused_dttm, reserved_dttm, claimed_dttm, active_dttm, blocked_dttm, last_login_dttm from auth_user where email = ?', array($inputs['email']));

#        $this->assertTrue(isset($user));
#        $this->assertEquals($response['user_id'],          $user['user_id']);
#        $this->assertEquals($response['email'],            $user['email']);
#        $this->assertEquals($response['user_salt'],        $user['salt']);
#        $this->assertEquals($response['algorithm'],        $user['algorithm']);
#        $this->assertEquals($response['algorithm_option'], $user['algorithm_option']);
#        $this->assertEquals('U',                           $user['status']);
#        $this->assertTrue(isset(                           $user['unused_dttm']));
#        $this->assertNull(                                 $user['reserved_dttm']);
#        $this->assertNull(                                 $user['claimed_dttm']);
#        $this->assertNull(                                 $user['active_dttm']);
#        $this->assertNull(                                 $user['blocked_dttm']);
#        $this->assertNull(                                 $user['last_login_dttm']);

#        $owner = $authdb->get_hash('select owner_id, owner_name, owner_type from auth_owner where owner_name = ?', array($inputs['email']));
#        $this->assertEquals($response['user_id'],          $owner['owner_id']);
#        $this->assertEquals($response['email'],        $owner['owner_name']);
#        $this->assertEquals('P',                          $owner['owner_type']);

#        $group = $authdb->get_hash('select group_id, group_name, group_long_name, owner_user_id from auth_group where group_name = ?', array($inputs['email']));
#        $this->assertNull($group);

#        $group_user_membs = $authdb->get_hashes('select group_id, user_id, all_perm_ind, status from auth_group_user_memb where user_id = ?', array($response['user_id']));
#        $this->assertCount(0, $group_user_membs);
#    }

#    # http://localhost/spadkins/apps/sitefront/front-framework/api.php?_dc=1372801881823&email=spadkins&email=&nick_name=&first_name=&middle_name=&last_name=&birth_date=&cell_phone=&address1=&city=&state_code=&postal_code=&country_code=&op=register&x=139612459223aa788d35f52d0274678006080d2436527614193b9bdd50b4ffd7

#    # NOTE: WHY NOT REQUIRE client_connection_token? recaptcha_challenge_field?
#    /** 
#     * @depends testReserveUserWhereUserIsSigningUp
#     */
#    public function testRegisterWithSignupModeSimpleAndFewDetails () {
#        global $context, $options;
#        $options['signup_mode']  = 'simple';
#        $options['trace_width']  = 0;
#        $options['trace']  = 1;
#        $options['debug_sql']  = 2;

#        $authentication            = $context->authentication();
#        $authdb                    = $context->authdb();
#        list($algorithm, $algorithm_option, $salt) = $authdb->get_row('select algorithm, algorithm_option, salt from auth_user where email = ?', self::$email);
#        self::$session_expire_dttm = date('Y-m-d\TH:i:s\Z', time()+3600);
#        self::$password_hash       = $authentication->createPasswordHash($algorithm, $algorithm_option, self::$password, $salt);
#        self::$auth_token          = $authentication->createAuthToken($algorithm, $algorithm_option, self::$password_hash, self::$session_expire_dttm);

#        $inputs = array(
#            'email'        => self::$email,
#            'x'            => self::$password_hash,
#            #'username'     => self::$username,
#            #'nick_name'    => '',
#            #'first_name'   => '',
#            #'middle_name'  => '',
#            #'last_name'    => '',
#            #'birth_date'   => '',
#            #'cell_phone'   => '',
#            #'address1'     => '',
#            #'city'         => '',
#            #'state_code'   => '',
#            #'postal_code'  => '',
#            #'country_code' => ''
#        );
#        $response = $this->callAjax('testRegisterWithSignupModeSimpleAndFewDetails', 'register', $inputs);
#        $this->assertEquals(1,               $response['success']);
#        $this->assertEquals(self::$username, $response['username']);
#        $this->assertTrue(isset($response['message']));

#        $authdb = $context->authdb();
#        $user = $authdb->get_hash('select user_id, username, email, salt, algorithm, algorithm_option, password_hash, status, unused_dttm, reserved_dttm, claimed_dttm, active_dttm, blocked_dttm, last_login_dttm from auth_user where email = ?', array($inputs['email']));

#        $this->assertTrue(isset($user));
#        $this->assertEquals($inputs['username'],          $user['username']);
#        $this->assertEquals($inputs['x'],                 $user['password_hash']);
#        $this->assertEquals('A',                          $user['status']);
#        $this->assertTrue(isset(                          $user['unused_dttm']));
#        $this->assertTrue(isset(                          $user['reserved_dttm']));
#        $this->assertTrue(isset(                          $user['claimed_dttm']));
#        $this->assertTrue(isset(                          $user['active_dttm']));
#        $this->assertNull(                                $user['blocked_dttm']);
#        $this->assertNull(                                $user['last_login_dttm']);

#        $owner = $authdb->get_hash('select owner_id, owner_name, owner_type from auth_owner where owner_name = ?', array($inputs['username']));
#        $this->assertEquals($user['user_id'],             $owner['owner_id']);
#        $this->assertEquals($user['username'],            $owner['owner_name']);
#        $this->assertEquals('P',                          $owner['owner_type']);

#        #$group_user_email = $authdb->get_hashes('select user_id, email, status from auth_user_email where user_id = ?', array($response['user_id']));
#        #$this->assertCount(0, $group_user_email);

#        $group = $authdb->get_hash('select group_id, group_name, group_long_name, owner_user_id from auth_group where group_name = ?', array($inputs['username']));
#        $this->assertTrue($group != null);
#        $this->assertEquals($user['user_id'],             $group['group_id']);
#        $this->assertEquals($user['username'],            $group['group_name']);
#        $this->assertEquals($user['username'],            $group['group_long_name']);
#        $this->assertEquals($user['user_id'],             $group['owner_user_id']);

#        $group_user_membs = $authdb->get_hashes('select group_id, user_id, all_perm_ind, status from auth_group_user_memb where user_id = ?', array($user['user_id']));
#        $this->assertCount(1, $group_user_membs);
#    }

    private function callAjax ($testMethod, $service, $inputs) {
        global $options;
        $url = $options['apps_urldir'] . '/sitefront/front-framework/api.php/service/auth/' . $service;
        fwrite(self::$fh, "##########################################################################\n");
        fwrite(self::$fh, "# TEST: $testMethod\n");
        fwrite(self::$fh, "# URL:  $url\n");
        fwrite(self::$fh, "##########################################################################\n");
        fwrite(self::$fh, "INPUTS:\n");
        fwrite(self::$fh, print_r($inputs,true));
        #$success = curl_setopt(self::$ua, CURLOPT_VERBOSE, true);
        $success = curl_setopt(self::$ua, CURLOPT_URL, $url);
        if (!$success) throw new \Exception('Ajax call prep failed (CURLOPT_URL)');
        $success = curl_setopt(self::$ua, CURLOPT_POSTFIELDS, $inputs);
        if (!$success) throw new \Exception('Ajax call prep failed (CURLOPT_POSTFIELDS)');
        $json = curl_exec(self::$ua);
        if (!$json) throw new \Exception('Ajax call failed (POST)');
        $response = json_decode($json, true);
        fwrite(self::$fh, "OUTPUTS:\n");
        fwrite(self::$fh, print_r($response,true));
        return($response);
    }
}

